package com.dotflat.rest.utils;

import com.dotflat.rest.PO.AreableObjectBasePO;
import com.matt.commons.exception.BusinessException;
import com.matt.foundation.model.ErrorCode;
import org.apache.commons.lang3.StringUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.List;

public class PredicatesUtils {

    public static <T> T getVal(String val, Class<T> type) {
        // 把val转换成type类型返回 比如说getVal("123",Integer.class) 返回一个123
        T value = null;
        try {
            Constructor<T> constructor = type.getConstructor(String.class);
            constructor.setAccessible(true);
            value = constructor.newInstance(val);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return value;
    }

    public static <T1> void generate(Root<T1> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder,
                                          Object param, List<Predicate> predicates)  {
        generate(root, query, criteriaBuilder, param, predicates, false);
    }

    public static <T1> void generate(Root<T1> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder,
                                                   Object param, List<Predicate> predicates, boolean uniqueFilter/*重复检查*/)  {

        //反射获取Class的属性（Field表示类中的成员变量）
        Class clazz = null;
        do{
            if (clazz == null){
                clazz = param.getClass();
            }else{
                clazz = clazz.getSuperclass();
            }
            Field[] fileds = clazz.getDeclaredFields();
            //获取最新数据，解决部分更新时jpa其他字段设置null问题
            for (Field field : fileds) {

                //获取授权
                field.setAccessible(true);

                //属性名称
                String fieldName = field.getName();

                //属性的值
                Object fieldValue = null;
                try {
                    fieldValue = field.get(param);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                    return;
                }

                //处理值
                if (uniqueFilter){
                    if (!field.isAnnotationPresent(UniqueField.class)) {
                        //过滤唯一条件
                        continue;
                    }

                    //指定唯一约束字段值
                    UniqueField ann = field.getAnnotation(UniqueField.class);
                    if (StringUtils.isNotBlank(ann.value())){
                        fieldValue = getVal(ann.value(), field.getType());
                    }
                }

                //找出值为空的属性，值为空则为忽略属性，或者被NotFound标注，我们复制的时候不进行赋值
                if(fieldValue != null){
                    if ((fieldValue instanceof String && StringUtils.isEmpty((String)fieldValue))){
                        //空字符串直接略过
                        continue;
                    }

                    if (field.isAnnotationPresent(LikeableField.class) && !uniqueFilter) {
                        //模糊查找
                        Predicate p = criteriaBuilder.like(root.get(fieldName), "%" + fieldValue + "%");
                        predicates.add(p);
                    }else if (field.isAnnotationPresent(QueryInField.class)) {
                        QueryInField ann = field.getAnnotation(QueryInField.class);
                        if (StringUtils.isNotBlank(ann.value()) && fieldValue != null && fieldValue instanceof Iterable) {
                            Iterable iter = (Iterable)fieldValue;
                            if (iter.iterator().hasNext()) {
                                CriteriaBuilder.In<Object> inClause = criteriaBuilder.in(root.get(ann.value()));
                                for (Object o : iter) {
                                    inClause.value(o);
                                }

                                predicates.add(inClause);
                            }
                        }
                    }else if (field.isAnnotationPresent(RangeField.class)) {
                        RangeField ann = field.getAnnotation(RangeField.class);

                        if (StringUtils.isNotBlank(ann.value()) && fieldValue != null && fieldValue instanceof Comparable) {
                            Predicate p = null;
                            if (ann.operator() == '<' && ann.eq()){
                                p = criteriaBuilder.lessThanOrEqualTo(root.get(ann.value()), (Comparable)fieldValue);
                            }else if (ann.operator() == '<' && !ann.eq()){
                                p = criteriaBuilder.lessThan(root.get(ann.value()), (Comparable)fieldValue);
                            }else if (ann.operator() == '>' && !ann.eq()){
                                p = criteriaBuilder.greaterThan(root.get(ann.value()), (Comparable)fieldValue);
                            }else if (ann.operator() == '>' && ann.eq()){
                                p = criteriaBuilder.greaterThanOrEqualTo(root.get(ann.value()), (Comparable)fieldValue);
                            }else {
                                throw new BusinessException(ErrorCode.VERSION_ERROR, "意料之外的运算符");
                            }

                            predicates.add(p);
                        }
                    }else if("areaId".equals(fieldName)) {
                        //areaId 为空时也需要查出来
                        Predicate p1 = criteriaBuilder.equal(root.get(fieldName), fieldValue);
                        if (uniqueFilter){
                            //重复检查时不需要检查areaId为空的情况
                            predicates.add(p1);
                        }else {
                            Predicate p2 = criteriaBuilder.isNull(root.get(fieldName));
                            predicates.add(criteriaBuilder.or(p1, p2));
                        }
                    }else{
                        //精确
                        Predicate p = criteriaBuilder.equal(root.get(fieldName), fieldValue);
                        predicates.add(p);
                    }
                }
            }
        }while (clazz != AreableObjectBasePO.class && clazz != Object.class && clazz != null);

    }


}
